package com.hardware.view.service;

import com.hardware.dll.AidierDLL;
import com.hardware.entity.CardInfo;
import com.hardware.entity.Respond;
import com.hardware.enums.AidierStatus;
import com.hardware.enums.HasKey;
import com.hardware.utils.MyDateUtil;
import com.sun.jna.Memory;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.LongByReference;
import com.sun.jna.ptr.PointerByReference;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.ChoiceBox;

import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.Optional;

/**
 * 功能测试
 *
 * @作者 韩宗森
 * @创建时间 2024年11月05日 11:57
 */
public class FunctionService {

    /**
     * 给下拉框枚举
     *
     * @param enumClass
     * @param <T>
     * @return
     */
    public <T extends Enum<T>> ObservableList<T> getEnumItems(Class<T> enumClass) {
        return FXCollections.observableArrayList(enumClass.getEnumConstants());
    }

    /**
     * 初始化下拉框
     *
     * @param choiceBox
     * @param enumClass
     * @param <T>
     */
    public <T extends Enum<T> & HasKey> void initializeChoiceBox(ChoiceBox<T> choiceBox, Class<T> enumClass, Integer key) {
        ObservableList<T> items = getEnumItems(enumClass);
        choiceBox.setItems(items);
        // choiceBox.setValue(items.get(0));

        // 尝试找到与key对应的枚举值
        Optional<T> defaultValue = Arrays.stream(enumClass.getEnumConstants())
                .filter(item -> item.getKey().equals(key))
                .findFirst();

        // 如果找到了对应的枚举值，则设置为默认值
        if (defaultValue.isPresent()) {
            choiceBox.setValue(defaultValue.get());
        } else {
            // 如果没有找到，默认设置第一个元素
            if (!items.isEmpty()) {
                choiceBox.setValue(items.get(0));
            }
        }
    }

    /**
     * 设置串口
     *
     * @param doorSoftwareKey 指定门锁系统
     * @param portKey         串口号
     * @param encoderKey      发行机类型
     * @param tmEncoderKey    TM发行机类型
     * @return
     */
    public int setPort(Integer doorSoftwareKey, Integer portKey, Integer encoderKey, Integer tmEncoderKey) {

        int ret = AidierDLL.INSTANCE.SetPort(doorSoftwareKey, portKey, encoderKey, tmEncoderKey);
        AidierStatus aidierStatus = AidierStatus.fromKey(ret);
        System.out.println(MyDateUtil.currentTime() + "设置串口 SetPort()" + "状态码: " + aidierStatus.getKey() + ", 说明: " + aidierStatus.getValue());

        return ret;
    }

    /**
     * Beep(蜂鸣器)
     *
     * @return
     */
    public int beep(int sound) {
        // 声音和LED状态。11-绿灯1秒，长叫一声；12-红灯1秒，长叫一声；15-红灯1秒，短叫两声；16-短叫一声。
        int ret = AidierDLL.INSTANCE.Reader_Beep(sound);
        AidierStatus aidierStatus = AidierStatus.fromKey(ret);
        System.out.println(MyDateUtil.currentTime() + "beep Reader_Beep():状态码: " + aidierStatus.getKey() + ", 说明: " + aidierStatus.getValue() + sound);
        return ret;
    }

    /**
     * 初始化
     *
     * @param softwareKey  指定门锁系统
     * @param serverStr    指定门锁系统数据库安装的服务器
     * @param usernameStr  用户名，用于门锁系统记录操作人员。
     * @param portKey      串口号，1-COM1，2-COM2，3-COM3，4-COM4依次类推。
     * @param encoderKey   发行机类型，0-手动发行机，1-自动发行机，2-MSR206（磁卡）。
     * @param tmEncoderKey TM发行机类型，1-DS9097E，5-DS9097U
     * @return
     */
    public int doorInit(Integer softwareKey, String serverStr, String usernameStr, Integer portKey, Integer encoderKey, Integer tmEncoderKey) {
        System.out.println(MyDateUtil.currentTime() + "初始化 doorInit():  softwareKey: " + softwareKey
                + "; serverStr: " + serverStr
                + "; usernameStr: " + usernameStr
                + "; portKey: " + portKey
                + "; encoderKey: " + encoderKey
                + "; tmEncoderKey: " + tmEncoderKey);
        try {
            int software = softwareKey;
            byte[] server = serverStr.getBytes("GBK");
            byte[] username = usernameStr.getBytes("GBK");
            int port = portKey;
            int Encoder = encoderKey;
            int TMEncoder = tmEncoderKey;
            // 开始 初始化
            int ret = AidierDLL.INSTANCE.Init(software, server, username, port, Encoder, TMEncoder);

            AidierStatus aidierStatus = AidierStatus.fromKey(ret);


            String msg = "状态码: " + aidierStatus.getKey() + ", 说明: " + aidierStatus.getValue();
            System.out.println("接口初始化: " + msg);
            return ret;
        } catch (UnsupportedEncodingException e) {
            System.out.println("String转byte 有异常...");
            e.printStackTrace();
        }

        return -1;
    }

    /**
     * 关闭资源接口
     *
     * @return
     */
    public int close() {
        int ret = AidierDLL.INSTANCE.EndSession();
        AidierStatus aidierStatus = AidierStatus.fromKey(ret);
        String msg = "状态码: " + aidierStatus.getKey() + ", 说明: " + aidierStatus.getValue();
        System.out.println("结束: " + msg);
        return ret;
    }

    /**
     * 复制卡
     *
     * @param roomNumText
     * @param publicWayStr
     * @param stimeText
     * @param guestNameText
     * @param guestIdText
     * @param isCover
     * @param cardNumText
     * @return
     */
    public int copyCard(String roomNumText, String publicWayStr, String stimeText, String guestNameText, String guestIdText, int isCover, String cardNumText) {
        System.out.println("复制卡参数: roomNumText: " + roomNumText
                + "; publicWayStr: " + publicWayStr
                + "; stimeText: " + stimeText
                + "; guestNameText: " + guestNameText
                + "; guestIdText: " + guestIdText
                + "; isCover: " + isCover
                + "; cardNumText: " + cardNumText);
        try {
            // 先转字符
            byte[] room = roomNumText.getBytes("GBK"); // 6字节字符串，必须是门锁系统设置的房号
            byte[] gate = publicWayStr.getBytes("GBK"); // 公共通道，字符串参数，“00”表示按默认授权通道，“99”表示授权所有公共通道，其他为指定通道代码。例如：“010203”表示授权01、02、03三个通道。
            byte[] stime = stimeText.getBytes("GBK"); //起止时间
            byte[] guestname = guestNameText.getBytes("GBK");
            byte[] guestid = guestIdText.getBytes("GBK");
            int overflag = isCover;
            long cardno = Long.parseLong(cardNumText);

            int ret = AidierDLL.INSTANCE.DupKey(room, gate, stime, guestname, guestid, overflag, cardno, null, null);
            AidierStatus aidierStatus = AidierStatus.fromKey(ret);
            System.out.println(MyDateUtil.currentTime() + "复制卡 DupKey():状态码: " + aidierStatus.getKey() + ", 说明: " + aidierStatus.getValue());

            return ret;
        } catch (UnsupportedEncodingException e) {
            System.out.println("String转byte 有异常...");
            e.printStackTrace();
        }
        return -1;
    }

    /**
     * 发卡
     *
     * @param roomNumText
     * @param publicWayStr
     * @param stimeText
     * @param guestNameText
     * @param guestIdText
     * @param isCover
     * @param cardNumText
     * @return
     */
    public int writeCard(String roomNumText, String publicWayStr, String stimeText, String guestNameText, String guestIdText, int isCover, String cardNumText) {
        System.out.println("发卡参数: roomNumText: " + roomNumText
                + "; publicWayStr: " + publicWayStr
                + "; stimeText: " + stimeText
                + "; guestNameText: " + guestNameText
                + "; guestIdText: " + guestIdText
                + "; isCover: " + isCover
                + "; cardNumText: " + cardNumText);
        try {
            // 先转字符
            byte[] room = roomNumText.getBytes("GBK"); // 6字节字符串，必须是门锁系统设置的房号
            byte[] gate = publicWayStr.getBytes("GBK"); // 公共通道，字符串参数，“00”表示按默认授权通道，“99”表示授权所有公共通道，其他为指定通道代码。例如：“010203”表示授权01、02、03三个通道。
            byte[] stime = stimeText.getBytes("GBK"); //起止时间
            byte[] guestname = guestNameText.getBytes("GBK");
            byte[] guestid = guestIdText.getBytes("GBK");
            int overflag = isCover;
            long cardno = Long.parseLong(cardNumText);
            byte[] track1 = new  byte[31];
            byte[] track2 = new  byte[31];


            int ret = AidierDLL.INSTANCE.NewKey(room, gate, stime, guestname, guestid, overflag, cardno, track1, track2);
            AidierStatus aidierStatus = AidierStatus.fromKey(ret);
            System.out.println(MyDateUtil.currentTime() + "写卡 NewKey():状态码: " + aidierStatus.getKey() + ", 说明: " + aidierStatus.getValue());

            return ret;
        } catch (UnsupportedEncodingException e) {
            System.out.println("String转byte 有异常...");
            e.printStackTrace();
        }
        return -1;
    }

    /**
     * 读卡
     *
     * @return
     */
    public Respond readCard() {
        System.out.println("读卡...");
        Respond respond = new Respond();
        respond.setStatus(-1);

/*
        char[] room = new char[51];
        char[] gate = new char[51];
        char[] stime = new char[51];
        char[] gname = new char[51];
        char[] gid = new char[51];
        char[] unused1 = null;
        char[] unused2 = null;
        int[] cardno = new int[1];
        int[] status = new int[1];
*/

        /*PointerByReference room = new PointerByReference();
        PointerByReference gate = new PointerByReference();
        PointerByReference stime = new PointerByReference();
        PointerByReference gname = new PointerByReference();
        PointerByReference gid = new PointerByReference();
        PointerByReference unused1 = new PointerByReference();
        PointerByReference unused2 = new PointerByReference();
        IntByReference cardno = new IntByReference();
        IntByReference status = new IntByReference();

        int ret = AidierDLL.INSTANCE.ReadCard(room, gate, stime, gname, gid, unused1, unused2, cardno, status);*/

     /*   // 分配内存
        Memory room = new Memory(51);
        Memory gate = new Memory(51);
        Memory stime = new Memory(51);
        Memory gname = new Memory(51);
        Memory gid = new Memory(51);
        Memory unused1 = null;
        Memory unused2 = null;
        IntByReference cardno = new IntByReference();
        IntByReference status = new IntByReference();
        int ret = AidierDLL.INSTANCE.ReadCard(room, gate, stime, gname, gid, unused1, unused2, cardno, status);*/


        String room1 = null;
        long room2 = 0;
        String gate1 = null;
        String stime1 = null;
        String guestname1 = null;
        String guestid1 = null;
        String track11 = null;
        String track21 = null;
        String cardno1 = null;
        String st1 = null;

        byte[] room = new byte[64]; // 接收返回的房号，建议10字节。
        byte[] gate = new byte[64]; // 接收返回的授权公共通道
        byte[] stime = new byte[64]; // 起止时间，24字节字符串
        byte[] guestname = new byte[64]; // 接收返回的客人姓名
        byte[] guestid = new byte[64]; // 接收返回的客人ID
        byte[] track1 = new byte[20]; // 接收返回的客人ID
        byte[] track2 = new byte[20]; // 接收返回的客人ID
        long cardno = 0; // 接收返回的卡号
        int st = 0; // 整形指针，接收返回的卡状态，1-正常使用，3-正常注销，4-遗失注销，5-损毁注销，6-自动注销。可以为NULL。

        // 读卡
        int ret = AidierDLL.INSTANCE.ReadCard(room, gate, stime, guestname, guestid, null, null, cardno, st);

//        int ret = AidierDLL.INSTANCE.ReadCard(room, gate, stime, gname, gid, unused1, unused2, cardno, status);
//        int ret = AidierDLL.INSTANCE.ReadCard(room, gate, stime, gname, gid, unused1, unused2, cardno, status);

//        int ret = AidierDLL.INSTANCE.ReadCard(room1, null, stime1, null, null, null, null, cardno, st);
//        int ret = AidierDLL.INSTANCE.ReadCard("0", "0", "0", "0", "0", null, null, 0);
//        int ret = AidierDLL.INSTANCE.ReadCard(room1,gate1,stime1,guestname1,guestid1,track11,track21,cardno1,st1);

//        int ret = AidierDLL.INSTANCE.ReadCard(room1,gate1,stime1,guestname1,guestid1,track11,track21,cardno); // 这个有问题
//        int ret = AidierDLL.INSTANCE.ReadCard(room1,gate1,stime1,guestname1,guestid1,track11,track21); // 参数错误
//        int ret = AidierDLL.INSTANCE.ReadCard(room1,gate1,stime1,guestname1,guestid1,track11); // 参数错误
//        int ret = AidierDLL.INSTANCE.ReadCard(room1,gate1,stime1,guestname1,guestid1); // 参数错误
//        int ret = AidierDLL.INSTANCE.ReadCard(room1,gate1,stime1,guestname1); // 参数错误
//        int ret = AidierDLL.INSTANCE.ReadCard(room1,gate1,stime1); // 参数错误
//        int ret = AidierDLL.INSTANCE.ReadCard(room1,gate1); // 参数错误
//        int ret = AidierDLL.INSTANCE.ReadCard(room1); // Invalid memory access
//        int ret = AidierDLL.INSTANCE.ReadCard(room2); // 参数错误
//        int ret = AidierDLL.INSTANCE.ReadCard(); // Invalid memory access


        AidierStatus aidierStatus = AidierStatus.fromKey(ret);
        String msg = "状态码: " + aidierStatus.getKey() + ", 说明: " + aidierStatus.getValue();
        System.out.println("读卡 ReadCard(): " + msg);


        CardInfo cardInfo = new CardInfo();
        try {
            String roomOut = new String(room, "GBK").trim();
            String gateOut = new String(gate, "GBK").trim();
            String stimeOut = new String(stime, "GBK").trim();
            String guestnameOut = new String(guestname, "GBK").trim();
            String guestidOut = new String(guestid, "GBK").trim();

            System.out.println(MyDateUtil.currentTime()
                    + "roomOut: " + roomOut
                    + ", gateOut: " + gateOut
                    + ", stimeOut: " + stimeOut
                    + ", guestnameOut: " + guestnameOut
                    + ", guestidOut: " + guestidOut
                    + ", cardnoOut: " + cardno
                    + ", st: " + st
            );
            cardInfo.setRoom(roomOut);
            cardInfo.setGate(gateOut);
            if (stimeOut.length() > 0) {
                cardInfo.setStarTime(stimeOut.substring(0, 12));
                cardInfo.setEndTime(stimeOut.substring(12, 24));
            }
            cardInfo.setGuestName(guestnameOut);
            cardInfo.setGuestId(guestidOut);
            cardInfo.setCardno(cardno);
            cardInfo.setCardStatus(st);


            respond.setMsg(msg);
            respond.setData(cardInfo);
            respond.setStatus(ret);

            return respond;
        } catch (UnsupportedEncodingException e) {
            System.out.println("读卡: byte[] 转 String 异常...");
            e.printStackTrace();
        }
        return respond;
    }
}
